package com.whately.core.database.util;

import com.whately.core.base.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;

@Slf4j
public class MybatisCriteriaHelper {

    /**
     * 通过反射实现调用
     */
    public static void selfDefineCriterion(Object criteria, String columnName, MybatisOperatorEnum mybatisOperatorEnum, Object value){
        if(mybatisOperatorEnum==null){
            throw new ServiceException(400,"mybatisOperatorEnum not allowed null");
        }

        checkParam(columnName);

        String methodName="addCriterion";
        Class[] paramType = new Class[]{String.class,Object.class,String.class};
        String property=columnName;
        Method method = ReflectionUtils.findMethod(criteria.getClass(),methodName,paramType);
        method.setAccessible(true);
        ReflectionUtils.invokeMethod(method,criteria,columnName+mybatisOperatorEnum.getOperator(), value, property);
    }

    public static void selfDefineCriterionFunctionInstr(Object criteria,String conditionColumn,String  value,  MybatisOperatorEnum mybatisOperatorEnum,Integer operatorResult){
        if(mybatisOperatorEnum==null){
            throw new ServiceException(400," func instr mybatisOperatorEnum not allowed null");
        }

        checkParam(conditionColumn);

        String methodName="addCriterion";
        Class[] paramType = new Class[]{String.class,Object.class,String.class};
        String property=conditionColumn;
        Method method = ReflectionUtils.findMethod(criteria.getClass(),methodName,paramType);
        method.setAccessible(true);

        String newCon = String.format(" instr(%s,'%s') ",conditionColumn, escapeSql(value));
        ReflectionUtils.invokeMethod(method,criteria,newCon+mybatisOperatorEnum.getOperator(),operatorResult, property);
    }

    public static void selfDefineCriterionBetweenOrNot(Object criteria,String columnName,MybatisOperatorEnum mybatisOperatorEnum, Object value1, Object value2){
        if(mybatisOperatorEnum!=MybatisOperatorEnum.between&&mybatisOperatorEnum!=MybatisOperatorEnum.NotBetween){
            throw new ServiceException(400,"only between or between not allowed");
        }

        checkParam(columnName);

        String methodName="addCriterion";
        Class[] paramType = new Class[]{String.class,Object.class,Object.class,String.class};
        String property=columnName;
        Method method = ReflectionUtils.findMethod(criteria.getClass(),methodName,paramType);
        method.setAccessible(true);
        ReflectionUtils.invokeMethod(method,criteria,columnName+mybatisOperatorEnum.getOperator(), value1,value2, property);
    }

    private static String escapeSql(String str) {
        return str == null ? null : StringUtils.replace(str, "'", "''");
    }

    /**
     * 列名，以字母或者_开头，
     * @param columnName
     */
    private static void checkParam(String columnName){
        if(StringUtils.isBlank(columnName)){
            throw new ServiceException(400,"column name is not correct format,not null");
        }
        String con_new =columnName.trim();
        String reg = "^[_a-zA-Z][a-zA-Z0-9_]*$";
        if(!con_new.matches(reg)){
            log.error("column name is not correct format ,column name {} ",columnName);
            throw new ServiceException(400,"column name is not correct format");
        }
    }
}
